/*
 *  WellTemperament.cpp
 *  SoundController0002
 *
 *  Created by jiro on 10/09/26.
 *  Copyright 2010 jiro music. All rights reserved.
 *
 */


#include "WellTemperament.h"

namespace sc
{

double WellTemperament::baseFrequency = 440.0;

double WellTemperament::GetFrequency( Note::MidiNumber number )
{
	int delta = number - Note::A4;
	double freq = pow( 2.0, delta / 12.0 ) * baseFrequency;
	return freq;
}

double WellTemperament::GetFrequency( Note::Id noteId, int octave )
{
	switch ( noteId ) {
	case Note::Mute:
		return 0.0;
	case Note::A:
		return baseFrequency * pow( 2.0, octave ) * pow( 2.0,  0. / 12. );
	case Note::ASharp:
		return baseFrequency * pow( 2.0, octave ) * pow( 2.0,  1. / 12. );
	case Note::B:
		return baseFrequency * pow( 2.0, octave ) * pow( 2.0,  2. / 12. );
	case Note::C:
		return baseFrequency * pow( 2.0, octave ) * pow( 2.0,  3. / 12. );
	case Note::CSharp:
		return baseFrequency * pow( 2.0, octave ) * pow( 2.0,  4. / 12. );
	case Note::D:
		return baseFrequency * pow( 2.0, octave ) * pow( 2.0,  5. / 12. );
	case Note::DSharp:
		return baseFrequency * pow( 2.0, octave ) * pow( 2.0,  6. / 12. );
	case Note::E:
		return baseFrequency * pow( 2.0, octave ) * pow( 2.0,  7. / 12. );
	case Note::F:
		return baseFrequency * pow( 2.0, octave ) * pow( 2.0,  8. / 12. );
	case Note::FSharp:
		return baseFrequency * pow( 2.0, octave ) * pow( 2.0,  9. / 12. );
	case Note::G:
		return baseFrequency * pow( 2.0, octave ) * pow( 2.0, 10. / 12. );
	case Note::GSharp:
		return baseFrequency * pow( 2.0, octave ) * pow( 2.0, 11. / 12. );
	default:
		return 0;
	}
}

Note::MidiNumber WellTemperament::GetMidiNoteNumber( double frequency )
{
	int octave = 0;
	double ratio;
	if ( frequency >= baseFrequency )
	{
		ratio = frequency / baseFrequency;
		while ( ratio >= 2 )
		{
			ratio /= 2;
			octave++;
		}
	}
	else
	{
		ratio = baseFrequency / frequency;
		octave = -1;
		while ( ratio > 2 )
		{
			ratio /= 2;
			octave--;
		}
	}

	for ( int i = 0; i < Note::NoteIdCount; i++ )
	{
		Note::MidiNumber number = static_cast< Note::MidiNumber >( Note::A4 + octave * Note::NoteIdCount + i );
		if ( fabs( frequency - GetFrequency( number ) ) < calculationError )
		{
			return number;
		}
	}
	return Note::MidiNumberMute;
}

bool WellTemperament::IsEqual( double v0, double v1 )
{
	if ( fabs( v1 - v0 ) < calculationError )
	{
		return true;
	}
	return false;
}

}
